﻿using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Linq;

namespace WebsiteStructureAnalyzer
{
    /// <summary>
    /// 网站结构分析器
    /// </summary>
    public class WebsiteStructureCrawler
    {
        private readonly HttpClient _httpClient;
        private readonly HashSet<string> _visitedUrls;
        private readonly int _maxDepth;

        public WebsiteStructureCrawler(int maxDepth = 2)
        {
            _httpClient = new HttpClient();
            _httpClient.DefaultRequestHeaders.Add("User-Agent",
                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36");
            _httpClient.Timeout = TimeSpan.FromSeconds(30);
            _visitedUrls = new HashSet<string>();
            _maxDepth = maxDepth;
        }

        /// <summary>
        /// 获取网站结构
        /// </summary>
        /// <param name="url">目标网站URL</param>
        /// <returns>网站结构信息</returns>
        public async Task<WebsiteStructure> GetWebsiteStructureAsync(string url)
        {
            var structure = new WebsiteStructure
            {
                RootUrl = url,
                CrawlTime = DateTime.Now
            };

            await CrawlPageAsync(url, structure, 0);
            return structure;
        }

        /// <summary>
        /// 递归爬取页面
        /// </summary>
        private async Task CrawlPageAsync(string url, WebsiteStructure structure, int currentDepth)
        {
            if (currentDepth > _maxDepth || _visitedUrls.Contains(url))
                return;

            _visitedUrls.Add(url);

            try
            {
                var response = await _httpClient.GetAsync(url);
                if (!response.IsSuccessStatusCode)
                    return;

                var htmlContent = await response.Content.ReadAsStringAsync();
                var pageInfo = ExtractPageInfo(url, htmlContent);

                structure.Pages.Add(pageInfo);

                // 提取并处理内部链接
                var internalLinks = ExtractInternalLinks(url, htmlContent);
                foreach (var link in internalLinks)
                {
                    if (!_visitedUrls.Contains(link))
                    {
                        await CrawlPageAsync(link, structure, currentDepth + 1);
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"爬取 {url} 时出错: {ex.Message}");
            }
        }

        /// <summary>
        /// 提取页面信息
        /// </summary>
        private PageInfo ExtractPageInfo(string url, string htmlContent)
        {
            var pageInfo = new PageInfo
            {
                Url = url,
                Title = ExtractTitle(htmlContent),
                Scripts = ExtractScripts(htmlContent),
                Stylesheets = ExtractStylesheets(htmlContent),
                Images = ExtractImages(htmlContent),
                Links = ExtractLinks(htmlContent),
                MetaTags = ExtractMetaTags(htmlContent),
                ExternalResources = ExtractExternalResources(htmlContent),
                Favicon = ExtractFavicon(htmlContent, url)
            };

            return pageInfo;
        }

        /// <summary>
        /// 提取页面标题
        /// </summary>
        private string ExtractTitle(string htmlContent)
        {
            var match = Regex.Match(htmlContent, @"<title>\s*(.*?)\s*</title>", RegexOptions.IgnoreCase | RegexOptions.Singleline);
            return match.Success ? match.Groups[1].Value.Trim() : "无标题";
        }

        /// <summary>
        /// 提取脚本文件
        /// </summary>
        private List<string> ExtractScripts(string htmlContent)
        {
            var scripts = new List<string>();
            var matches = Regex.Matches(htmlContent,
                @"<script[^>]+src\s*=\s*[""']([^""']+)[""'][^>]*>", RegexOptions.IgnoreCase | RegexOptions.Singleline);

            foreach (Match match in matches)
            {
                if (match.Success)
                    scripts.Add(match.Groups[1].Value);
            }

            return scripts.Distinct().ToList();
        }

        /// <summary>
        /// 提取样式表
        /// </summary>
        private List<string> ExtractStylesheets(string htmlContent)
        {
            var stylesheets = new List<string>();
            var matches = Regex.Matches(htmlContent,
                @"<link[^>]+href\s*=\s*[""']([^""']+\.css[^""']*)[""'][^>]*>", RegexOptions.IgnoreCase | RegexOptions.Singleline);

            foreach (Match match in matches)
            {
                if (match.Success)
                    stylesheets.Add(match.Groups[1].Value);
            }

            return stylesheets.Distinct().ToList();
        }

        /// <summary>
        /// 提取图片资源
        /// </summary>
        private List<string> ExtractImages(string htmlContent)
        {
            var images = new List<string>();
            var matches = Regex.Matches(htmlContent,
                @"<img[^>]+src\s*=\s*[""']([^""']+)[""'][^>]*>", RegexOptions.IgnoreCase | RegexOptions.Singleline);

            foreach (Match match in matches)
            {
                if (match.Success)
                    images.Add(match.Groups[1].Value);
            }

            return images.Distinct().ToList();
        }

        /// <summary>
        /// 提取网站图标
        /// </summary>
        private string ExtractFavicon(string htmlContent, string baseUrl)
        {
            var match = Regex.Match(htmlContent,
                @"<link[^>]+rel\s*=\s*[""'](?:shortcut\s+)?icon[""'][^>]+href\s*=\s*[""']([^""']+)[""']",
                RegexOptions.IgnoreCase | RegexOptions.Singleline);

            if (match.Success)
            {
                var faviconUrl = match.Groups[1].Value;
                // 处理相对路径
                if (faviconUrl.StartsWith("/"))
                {
                    var uri = new Uri(baseUrl);
                    faviconUrl = $"{uri.Scheme}://{uri.Host}{faviconUrl}";
                }
                else if (faviconUrl.StartsWith("./"))
                {
                    var uri = new Uri(baseUrl);
                    faviconUrl = $"{uri.Scheme}://{uri.Host}{faviconUrl.Substring(1)}";
                }
                return faviconUrl;
            }

            // 默认favicon位置
            var defaultUri = new Uri(baseUrl);
            return $"{defaultUri.Scheme}://{defaultUri.Host}/favicon.ico";
        }

        /// <summary>
        /// 提取所有链接
        /// </summary>
        private List<string> ExtractLinks(string htmlContent)
        {
            var links = new List<string>();
            var matches = Regex.Matches(htmlContent,
                @"<a[^>]+href\s*=\s*[""']([^""']+)[""'][^>]*>", RegexOptions.IgnoreCase | RegexOptions.Singleline);

            foreach (Match match in matches)
            {
                if (match.Success)
                    links.Add(match.Groups[1].Value);
            }

            return links.Distinct().ToList();
        }

        /// <summary>
        /// 提取Meta标签
        /// </summary>
        private List<MetaTag> ExtractMetaTags(string htmlContent)
        {
            var metaTags = new List<MetaTag>();
            var matches = Regex.Matches(htmlContent,
                @"<meta\s+([^>]+)>", RegexOptions.IgnoreCase | RegexOptions.Singleline);

            foreach (Match match in matches)
            {
                if (match.Success)
                {
                    var nameMatch = Regex.Match(match.Value,
                        @"name\s*=\s*[""']([^""']+)[""']", RegexOptions.IgnoreCase);
                    var contentMatch = Regex.Match(match.Value,
                        @"content\s*=\s*[""']([^""']+)[""']", RegexOptions.IgnoreCase);

                    if (nameMatch.Success && contentMatch.Success)
                    {
                        metaTags.Add(new MetaTag
                        {
                            Name = nameMatch.Groups[1].Value,
                            Content = contentMatch.Groups[1].Value
                        });
                    }
                }
            }

            return metaTags;
        }

        /// <summary>
        /// 提取外部资源
        /// </summary>
        private List<string> ExtractExternalResources(string htmlContent)
        {
            var resources = new List<string>();

            // 提取所有URL
            var urlMatches = Regex.Matches(htmlContent,
                @"(https?://[^\s""'<>]+)", RegexOptions.IgnoreCase | RegexOptions.Singleline);

            foreach (Match match in urlMatches)
            {
                if (match.Success)
                    resources.Add(match.Groups[1].Value);
            }

            return resources.Distinct().ToList();
        }

        /// <summary>
        /// 提取内部链接
        /// </summary>
        private List<string> ExtractInternalLinks(string baseUrl, string htmlContent)
        {
            var internalLinks = new List<string>();
            var uri = new Uri(baseUrl);
            var baseDomain = uri.Host;

            var matches = Regex.Matches(htmlContent,
                @"<a[^>]+href\s*=\s*[""']([^""']+)[""'][^>]*>", RegexOptions.IgnoreCase | RegexOptions.Singleline);

            foreach (Match match in matches)
            {
                if (match.Success)
                {
                    var link = match.Groups[1].Value;

                    // 处理相对链接
                    if (link.StartsWith("/"))
                    {
                        link = $"{uri.Scheme}://{baseDomain}{link}";
                    }
                    else if (link.StartsWith("./"))
                    {
                        link = $"{uri.Scheme}://{baseDomain}{link.Substring(1)}";
                    }
                    else if (!link.StartsWith("http"))
                    {
                        continue; // 跳过非HTTP链接
                    }

                    // 检查是否是同一域名的链接
                    try
                    {
                        var linkUri = new Uri(link);
                        if (linkUri.Host == baseDomain || linkUri.Host.EndsWith("." + baseDomain))
                        {
                            internalLinks.Add(link);
                        }
                    }
                    catch
                    {
                        // 忽略无效URL
                    }
                }
            }

            return internalLinks.Distinct().ToList();
        }

        public void Dispose()
        {
            _httpClient?.Dispose();
        }
    }

    /// <summary>
    /// 网站结构信息
    /// </summary>
    public class WebsiteStructure
    {
        public string RootUrl { get; set; }
        public DateTime CrawlTime { get; set; }
        public List<PageInfo> Pages { get; set; } = new List<PageInfo>();

        /// <summary>
        /// 打印网站结构
        /// </summary>
        public void PrintStructure()
        {
            Console.WriteLine($"网站结构分析 - {RootUrl}");
            Console.WriteLine($"爬取时间: {CrawlTime}");
            Console.WriteLine(new string('=', 50));

            foreach (var page in Pages)
            {
                Console.WriteLine($"\n页面: {page.Url}");
                Console.WriteLine($"标题: {page.Title}");

                if (!string.IsNullOrEmpty(page.Favicon))
                {
                    Console.WriteLine($"网站图标: {page.Favicon}");
                }

                if (page.Scripts.Count > 0)
                {
                    Console.WriteLine("脚本文件:");
                    foreach (var script in page.Scripts)
                        Console.WriteLine($"  - {script}");
                }

                if (page.Stylesheets.Count > 0)
                {
                    Console.WriteLine("样式表:");
                    foreach (var stylesheet in page.Stylesheets)
                        Console.WriteLine($"  - {stylesheet}");
                }

                if (page.Images.Count > 0)
                {
                    Console.WriteLine("图片资源:");
                    foreach (var image in page.Images.Take(5)) // 限制显示数量
                        Console.WriteLine($"  - {image}");
                }

                if (page.ExternalResources.Count > 0)
                {
                    Console.WriteLine("外部资源:");
                    foreach (var resource in page.ExternalResources.Take(10)) // 限制显示数量
                        Console.WriteLine($"  - {resource}");
                }

                if (page.MetaTags.Count > 0)
                {
                    Console.WriteLine("Meta标签:");
                    foreach (var meta in page.MetaTags.Take(5))
                        Console.WriteLine($"  - {meta.Name}: {meta.Content}");
                }
            }
        }
    }

    /// <summary>
    /// 页面信息
    /// </summary>
    public class PageInfo
    {
        public string Url { get; set; }
        public string Title { get; set; }
        public string Favicon { get; set; }
        public List<string> Scripts { get; set; } = new List<string>();
        public List<string> Stylesheets { get; set; } = new List<string>();
        public List<string> Images { get; set; } = new List<string>();
        public List<string> Links { get; set; } = new List<string>();
        public List<MetaTag> MetaTags { get; set; } = new List<MetaTag>();
        public List<string> ExternalResources { get; set; } = new List<string>();
    }

    /// <summary>
    /// Meta标签信息
    /// </summary>
    public class MetaTag
    {
        public string Name { get; set; }
        public string Content { get; set; }
    }
}